"""基于LLM的题目生成服务"""
import json
import re
import uuid
from typing import List, Dict, Any, Optional
from datetime import datetime
from app.ai.llm_service import get_llm_service


class LLMQuestionGenerator:
    """基于LLM的题目生成器"""
    
    def __init__(self):
        self.llm_service = get_llm_service()
    
    def _get_question_generation_prompt(
        self,
        subject: str,
        knowledge_point: str,
        difficulty: str = "medium",
        question_type: str = "single_choice",
        count: int = 1
    ) -> str:
        """
        生成题目生成提示词
        
        Args:
            subject: 科目（民法、刑法等）
            knowledge_point: 知识点
            difficulty: 难度（easy/medium/hard）
            question_type: 题目类型（single_choice/multiple_choice）
            count: 生成数量
            
        Returns:
            提示词文本
        """
        difficulty_desc = {
            "easy": "基础难度，考察基本概念和法条记忆",
            "medium": "中等难度，考察理解和应用能力",
            "hard": "高难度，考察综合分析能力和法律思维"
        }
        
        question_type_desc = {
            "single_choice": "单选题（4个选项，只有1个正确答案）",
            "multiple_choice": "多选题（4个选项，可能有2-4个正确答案）"
        }
        
        prompt = f"""你是一位专业的法考出题专家。请根据以下要求生成{count}道法考题目。

**科目**：{subject}
**知识点**：{knowledge_point}
**难度**：{difficulty}（{difficulty_desc.get(difficulty, '中等难度')}）
**题目类型**：{question_type_desc.get(question_type, '单选题')}

**题目要求**：
1. 题目内容必须准确、严谨，符合法考标准
2. 选项设计要具有干扰性，错误选项要合理但明显错误
3. 正确答案要有明确的法律依据
4. 解释要详细，说明为什么正确，为什么错误选项不对
5. 题目要考察对知识点的理解和应用，不仅仅是记忆

**输出格式**（JSON数组）：
```json
[
  {{
    "content": "题目内容（完整的题目描述）",
    "options": [
      "选项A：...",
      "选项B：...",
      "选项C：...",
      "选项D：..."
    ],
    "correct_answer": "选项C"（或["选项A", "选项C"]如果是多选题）,
    "explanation": "详细解释，包括：1) 正确答案的法律依据；2) 为什么其他选项错误；3) 相关知识点说明",
    "knowledge_points": ["知识点1", "知识点2"],
    "difficulty": "{difficulty}",
    "type": "{question_type}"
  }}
]
```

**重要**：
- 只返回JSON数组，不要其他文字说明
- 确保JSON格式正确，可以被解析
- 题目内容要符合法考实际出题风格
- 选项要平衡，避免明显错误或过于简单

请开始生成题目："""
        
        return prompt
    
    async def generate_question(
        self,
        subject: str,
        knowledge_point: str,
        difficulty: str = "medium",
        question_type: str = "single_choice"
    ) -> Optional[Dict[str, Any]]:
        """
        生成单个题目
        
        Args:
            subject: 科目
            knowledge_point: 知识点
            difficulty: 难度
            question_type: 题目类型
            
        Returns:
            生成的题目字典，如果生成失败返回None
        """
        try:
            prompt = self._get_question_generation_prompt(
                subject=subject,
                knowledge_point=knowledge_point,
                difficulty=difficulty,
                question_type=question_type,
                count=1
            )
            
            # 调用LLM生成
            response_text = await self.llm_service.generate_text(
                prompt,
                max_tokens=2000,
                temperature=0.7  # 适中的创造性
            )
            
            # 解析响应
            questions = self._parse_llm_response(response_text)
            if questions and len(questions) > 0:
                question = questions[0]
                # 添加元数据
                question["question_id"] = f"llm_gen_{uuid.uuid4().hex[:8]}"
                question["subject"] = self._map_subject_to_code(subject)
                question["category"] = subject
                question["generated_by"] = "LLM"
                question["generated_at"] = datetime.now().isoformat()
                question["source"] = "llm_generated"
                question["difficulty_score"] = self._get_difficulty_score(difficulty)
                question["wrong_count"] = 0
                question["correct_count"] = 0
                
                return question
            else:
                print(f"⚠️ [LLM生成] 解析失败，未生成有效题目")
                return None
                
        except Exception as e:
            print(f"❌ [LLM生成] 生成题目失败: {e}")
            return None
    
    async def generate_questions_batch(
        self,
        requirements: List[Dict[str, Any]],
        max_retries: int = 2
    ) -> List[Dict[str, Any]]:
        """
        批量生成题目
        
        Args:
            requirements: 生成要求列表，每个元素包含：
                - subject: 科目
                - knowledge_point: 知识点
                - difficulty: 难度
                - question_type: 题目类型（可选）
                - count: 生成数量（可选，默认1）
            max_retries: 最大重试次数
            
        Returns:
            生成的题目列表
        """
        generated_questions = []
        
        for req in requirements:
            subject = req.get("subject", "民法")
            knowledge_point = req.get("knowledge_point", "合同法")
            difficulty = req.get("difficulty", "medium")
            question_type = req.get("question_type", "single_choice")
            count = req.get("count", 1)
            
            # 批量生成（一次生成多个）
            if count > 1:
                try:
                    prompt = self._get_question_generation_prompt(
                        subject=subject,
                        knowledge_point=knowledge_point,
                        difficulty=difficulty,
                        question_type=question_type,
                        count=count
                    )
                    
                    response_text = await self.llm_service.generate_text(
                        prompt,
                        max_tokens=4000,  # 批量生成需要更多token
                        temperature=0.7
                    )
                    
                    questions = self._parse_llm_response(response_text)
                    if questions:
                        for q in questions:
                            q["question_id"] = f"llm_gen_{uuid.uuid4().hex[:8]}"
                            q["subject"] = self._map_subject_to_code(subject)
                            q["category"] = subject
                            q["generated_by"] = "LLM"
                            q["generated_at"] = datetime.now().isoformat()
                            q["source"] = "llm_generated"
                            q["difficulty_score"] = self._get_difficulty_score(difficulty)
                            q["wrong_count"] = 0
                            q["correct_count"] = 0
                            generated_questions.append(q)
                except Exception as e:
                    print(f"⚠️ [LLM批量生成] 失败: {e}，尝试单个生成")
                    # 回退到单个生成
                    for _ in range(count):
                        question = await self.generate_question(
                            subject, knowledge_point, difficulty, question_type
                        )
                        if question:
                            generated_questions.append(question)
            else:
                # 单个生成
                question = await self.generate_question(
                    subject, knowledge_point, difficulty, question_type
                )
                if question:
                    generated_questions.append(question)
        
        return generated_questions
    
    def _parse_llm_response(self, response_text: str) -> List[Dict[str, Any]]:
        """
        解析LLM响应，提取题目
        
        Args:
            response_text: LLM返回的文本
            
        Returns:
            题目列表
        """
        try:
            # 尝试提取JSON数组
            # 方法1：直接解析整个响应
            try:
                data = json.loads(response_text.strip())
                if isinstance(data, list):
                    return data
                elif isinstance(data, dict):
                    return [data]
            except:
                pass
            
            # 方法2：使用正则表达式提取JSON数组
            json_match = re.search(r'\[.*?\]', response_text, re.DOTALL)
            if json_match:
                try:
                    data = json.loads(json_match.group())
                    if isinstance(data, list):
                        return data
                except:
                    pass
            
            # 方法3：尝试提取单个JSON对象
            json_match = re.search(r'\{.*?\}', response_text, re.DOTALL)
            if json_match:
                try:
                    data = json.loads(json_match.group())
                    if isinstance(data, dict):
                        return [data]
                except:
                    pass
            
            print(f"⚠️ [LLM解析] 无法解析响应: {response_text[:200]}...")
            return []
            
        except Exception as e:
            print(f"❌ [LLM解析] 解析失败: {e}")
            return []
    
    def _map_subject_to_code(self, subject: str) -> str:
        """将中文科目名映射为英文代码"""
        mapping = {
            "民法": "civil_law",
            "民诉": "civil_procedure",
            "刑法": "criminal_law",
            "刑诉": "criminal_procedure",
            "行政": "administrative",
            "商经": "commercial",
            "三国": "international",
            "综合": "comprehensive"
        }
        return mapping.get(subject, "civil_law")
    
    def _get_difficulty_score(self, difficulty: str) -> float:
        """将难度等级转换为分数"""
        mapping = {
            "easy": 40.0,
            "medium": 60.0,
            "hard": 80.0
        }
        return mapping.get(difficulty, 60.0)
    
    def validate_question(self, question: Dict[str, Any]) -> tuple[bool, Optional[str]]:
        """
        验证题目格式和内容
        
        Args:
            question: 题目字典
            
        Returns:
            (是否有效, 错误信息)
        """
        # 检查必需字段
        required_fields = ["content", "options", "correct_answer", "explanation"]
        for field in required_fields:
            if field not in question:
                return False, f"缺少必需字段: {field}"
        
        # 检查选项数量
        options = question.get("options", [])
        if len(options) != 4:
            return False, f"选项数量不正确，应为4个，实际{len(options)}个"
        
        # 检查正确答案格式
        correct_answer = question.get("correct_answer")
        question_type = question.get("type", "single_choice")
        
        if question_type == "single_choice":
            if not isinstance(correct_answer, str):
                return False, "单选题的正确答案应为字符串"
            if not correct_answer.startswith("选项"):
                return False, "正确答案格式不正确，应为'选项A'、'选项B'等"
        elif question_type == "multiple_choice":
            if not isinstance(correct_answer, list):
                return False, "多选题的正确答案应为列表"
            if len(correct_answer) < 2:
                return False, "多选题至少应有2个正确答案"
        
        # 检查内容长度
        content = question.get("content", "")
        if len(content) < 20:
            return False, "题目内容过短"
        
        explanation = question.get("explanation", "")
        if len(explanation) < 50:
            return False, "解释内容过短"
        
        return True, None


# 全局实例
llm_question_generator = LLMQuestionGenerator()

